﻿using Common.Caching;
using Common.Configurations;
using Common.Enums;
using Domain.Entities.Tenants;
using Domain.Repositories;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace Domain.Services;

/// <summary>
/// 多租户服务
/// </summary>
public class MultiTenancyService : ISingletonDependency
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ICacheService _cacheService;

    public MultiTenancyService(
        IServiceProvider serviceProvider, 
        ICacheService cacheService)
    {
        _serviceProvider = serviceProvider;
        _cacheService = cacheService;
    }

    /// <summary>
    /// 初始化租户数据
    /// </summary>
    /// <returns></returns>
    public async Task InitializeAsync()
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var _optMultiTenancySettings = scope.ServiceProvider.GetRequiredService<IOptions<MultiTenancySettings>>();
            var defaultMultiTenancySettings = _optMultiTenancySettings.Value;
            if (!defaultMultiTenancySettings.Enabled) return;

            await RefreshAsync();

            var _multiTenantRepository = scope.ServiceProvider.GetRequiredService<IMultiTenantRepository>();
            var hasCustomMultiTenancyData = (await _multiTenantRepository.GetAllEnabledAsync()).Any();
            if (hasCustomMultiTenancyData) return;

            var _optDatabaseSettings = scope.ServiceProvider.GetRequiredService<IOptions<DatabaseSettings>>();
            var defaultDatabaseSettings = _optDatabaseSettings.Value;
            var defaultTenant = new Tenant();
            defaultTenant.Id = defaultMultiTenancySettings.TenancyDefaultName;
            defaultTenant.IsDefault = true;
            defaultTenant.Name = defaultMultiTenancySettings.TenancyDefaultName;
            defaultTenant.ConnectionString = defaultDatabaseSettings.ConnectionString;
            switch (defaultDatabaseSettings.DBProvider.ToLower())
            {
                case "sqlite":
                    defaultTenant.DbProviderType = DbProviderType.Sqlite;
                    break;
                case "mysql":
                    defaultTenant.DbProviderType = DbProviderType.MySql;
                    break;
                case "mssql":
                    defaultTenant.DbProviderType = DbProviderType.MsSql;
                    break;
                case "gostgresql":
                    defaultTenant.DbProviderType = DbProviderType.PostgreSql;
                    break;
                default:
                    throw new NotSupportedException($"Unsupported database provider type: {defaultTenant.DbProviderType}");
            }

            await _multiTenantRepository.AddOrEditAsync(defaultTenant);
            await RefreshAsync();
        }
    }

    /// <summary>
    /// 刷新租户数据
    /// </summary>
    /// <returns></returns>
    public async Task RefreshAsync()
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var _multiTenantRepository = scope.ServiceProvider.GetRequiredService<IMultiTenantRepository>();
            _cacheService.Remove(CaCheKeyExtensions.TenantCacheKey());
           await _cacheService.GetOrAddAsync(
                CaCheKeyExtensions.TenantCacheKey(),
                _multiTenantRepository.GetAllEnabledAsync);
        }
    }

    /// <summary>
    /// 根据租户Id获取租户数据
    /// </summary>
    /// <param name="tenantId"></param>
    /// <returns></returns>
    public Tenant GetTenantById(string tenantId)
    {
        return _cacheService.Get<List<Tenant>>(CaCheKeyExtensions.TenantCacheKey())?.First(x => x.Id == tenantId) ?? new Tenant();
    }

    /// <summary>
    /// 根据租户Id获取租户数据
    /// </summary>
    /// <returns></returns>
    public string GetCurrentTenantId(string? dbConnectionString = null)
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var _currentUserService = scope.ServiceProvider.GetRequiredService<ICurrentUserService>();

            var tenantId = _currentUserService.TenantId;
            if (string.IsNullOrWhiteSpace(tenantId))
            {
                var _httpContextAccessor = scope.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
                tenantId = _httpContextAccessor.HttpContext?.Request?.Headers["Tenant-Id"].ToString();
            }
            if (string.IsNullOrWhiteSpace(tenantId))
            {
                tenantId = _cacheService.Get<List<Tenant>>(CaCheKeyExtensions.TenantCacheKey())?.Find(x => x.IsDefault)?.Id;
            }
            if (dbConnectionString != null) 
            {
                tenantId = _cacheService.Get<List<Tenant>>(CaCheKeyExtensions.TenantCacheKey()).Find(x => x.ConnectionString == dbConnectionString)?.Id;
            }

            return tenantId ?? "";
        }
    }

    /// <summary>
    /// 是否为默认租户
    /// </summary>
    /// <returns></returns>
    public bool IsTenantDefault(string tenantId)
    {
        return tenantId == _cacheService.Get<List<Tenant>>(CaCheKeyExtensions.TenantCacheKey())?.Find(x => x.IsDefault)?.Id;
    }

    /// <summary>
    /// 是否为默认租户
    /// </summary>
    /// <returns></returns>
    public bool IsTenantDefault()
    {
        var isTenantDefault = IsTenantDefault(GetCurrentTenantId());
        return isTenantDefault;
    }

    /// <summary>
    /// 是否开启租户
    /// </summary>
    /// <returns></returns>
    public bool IsEnabled()
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var _optMultiTenancySettings = scope.ServiceProvider.GetRequiredService<IOptions<MultiTenancySettings>>();
            return _optMultiTenancySettings.Value.Enabled;
        }
    }

    /// <summary>
    /// 获取当前租户数据
    /// </summary>
    /// <returns></returns>
    public Tenant GetCurrentTenant()
    {
        return GetTenantById(GetCurrentTenantId());
    }

    /// <summary>
    /// 是否使用默认连接
    /// </summary>
    /// <returns></returns>
    public bool IsUseDefaultConnectionString()
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            var _currentUserService = scope.ServiceProvider.GetRequiredService<ICurrentUserService>();

            var tenantId = _currentUserService.TenantId;
            if (string.IsNullOrWhiteSpace(tenantId))
            {
                var _httpContextAccessor = scope.ServiceProvider.GetRequiredService<IHttpContextAccessor>();
                tenantId = _httpContextAccessor.HttpContext?.Request?.Headers["Tenant-Id"].ToString();
            }

            return string.IsNullOrWhiteSpace(tenantId);
        }
    }
}
